import { useRef, useEffect, useCallback, useContext } from 'react';
import { calculateVisibleItems } from '../helpers/utils';
import type { FlattenedTask } from '../types';
import GanttContext from '../context';
import { GanttConsts } from '../constants';

interface UseVirtualScrollReturn {
  startIndex: number;
  offsetY: number;
  totalHeight: number;
  visibleItems: FlattenedTask[];
  scrollbarHeight: number;
  scrollbarTop: number;
  maxScrollTop: number;
  handleScroll: (e: React.UIEvent<HTMLDivElement>) => void;
  handleWheel: (e: React.WheelEvent<HTMLDivElement>) => void;
  ganttContainerRef: React.RefObject<HTMLDivElement>;
}

export function useVirtualScroll(): UseVirtualScrollReturn {
  const { scrollTop, setScrollTop, setScrollLeft, scrollLeft, containerHeight, ganttWidth, containerWidth, hideTaskTable, flattenedTasks } = useContext(GanttContext)
  const ganttContainerRef = useRef<HTMLDivElement>(null);

  const ganttTableHeight = containerHeight - GanttConsts.HEADER_HEIGHT - GanttConsts.THEADER_HEIGHT;
  const ganttTableWidth = containerWidth - (hideTaskTable ? 0 : GanttConsts.TASKTABLE_WIDTH);
  const { startIndex, offsetY, totalHeight, visibleItems } = calculateVisibleItems(flattenedTasks, ganttTableHeight, scrollTop);
  const maxScrollTop = Math.max(0, totalHeight - ganttTableHeight);
  const maxScrollLeft = Math.max(0, ganttWidth - ganttTableWidth);

  // 计算滚动条相关数值
  const scrollbarHeight = Math.max((ganttTableHeight / totalHeight) * ganttTableHeight, 20);
  const scrollbarTop = maxScrollTop > 0 ? (scrollTop / maxScrollTop) * (ganttTableHeight - scrollbarHeight) : 0;

  // 使用ref来避免循环更新和抖动
  const isUpdatingScrollRef = useRef(false);
  const lastScrollTopRef = useRef(scrollTop);

  // 同步外部滚动到容器（避免频繁更新）
  useEffect(() => {
    if (ganttContainerRef.current && !isUpdatingScrollRef.current && scrollTop !== undefined && Math.abs(scrollTop - lastScrollTopRef.current) > 1) {
      ganttContainerRef.current.scrollTop = scrollTop;
      lastScrollTopRef.current = scrollTop;
    }
  }, [scrollTop]);

  // 使用节流来优化滚动性能
  const throttleTimeoutRef = useRef<NodeJS.Timeout | null>(null);

  // 处理容器滚动事件（使用节流优化性能）
  const handleScroll = useCallback((e: React.UIEvent<HTMLDivElement>) => {
    const newScrollTop = e.currentTarget.scrollTop;

    // 立即更新lastScrollTopRef以避免抖动
    lastScrollTopRef.current = newScrollTop;

    // 使用节流来减少更新频率
    if (throttleTimeoutRef.current) {
      clearTimeout(throttleTimeoutRef.current);
    }

    throttleTimeoutRef.current = setTimeout(() => {
      if (!isUpdatingScrollRef.current) {
        isUpdatingScrollRef.current = true;
        setScrollTop(newScrollTop);

        // 使用requestAnimationFrame来确保在下一帧重置标志
        requestAnimationFrame(() => {
          isUpdatingScrollRef.current = false;
        });
      }
    }, 8); // 减少到8ms以提高响应性
  }, [setScrollTop]);

  // 清理定时器
  useEffect(() => {
    return () => {
      if (throttleTimeoutRef.current) {
        clearTimeout(throttleTimeoutRef.current);
      }
    };
  }, []);

  // 处理鼠标滚轮事件（优化版本）
  const handleWheel = useCallback((e: React.WheelEvent<HTMLDivElement>) => {
    if (e.cancelable) {
      e.preventDefault();
    }

    // 滚动速度调节因子
    const scrollSpeed = 1.2;

    if (e.shiftKey) {
      // 处理水平滚动
      const deltaX = e.deltaX * scrollSpeed;
      const newScrollLeft = Math.max(0, Math.min(maxScrollLeft, scrollLeft + deltaX));

      // 只有当滚动位置真正改变时才更新
      if (newScrollLeft !== scrollLeft) {
        setScrollLeft(newScrollLeft);
      }
    } else {
      // 处理垂直滚动
      const deltaY = e.deltaY * scrollSpeed;
      const newScrollTop = Math.max(0, Math.min(maxScrollTop, scrollTop + deltaY));

      // 只有当滚动位置真正改变时才更新
      if (newScrollTop !== scrollTop) {
        setScrollTop(newScrollTop);
      }
    }
  }, [scrollTop, scrollLeft, maxScrollTop, maxScrollLeft, setScrollTop, setScrollLeft]);

  return {
    startIndex,
    offsetY,
    totalHeight,
    visibleItems,
    scrollbarHeight,
    scrollbarTop,
    maxScrollTop,
    handleScroll,
    handleWheel,
    ganttContainerRef: ganttContainerRef as React.RefObject<HTMLDivElement>,
  };
}